//
//  SHAnchorLiveView.m
//  Netease
//
//  Created by 王方伟 on 2017/8/25.
//  Copyright © 2017年 wfw. All rights reserved.
//

#import "SHAnchorLiveView.h"
#import "NTESLiveAudienceHandler.h"
#import "NTESSessionMsgConverter.h"
#import "NSDictionary+Extension.h"
#import "NTESLiveAnchorHandler.h"
#import "NTESPresentAttachment.h"
#import "NTESConnectQueueView.h"
#import "NTESDemoLiveroomTask.h"
#import "NTESPresentBoxView.h"
#import "NTESPresentBoxView.h"
#import "NSString+Extension.h"
#import "NTESLikeAttachment.h"
#import "NTESLiveInnerView.h"
#import "NTESTimerHolder.h"
#import "NTESDemoService.h"
#import <NIMAVChat/NIMAVChat.h>

typedef void(^NTESDisconnectAckHandler)(NSError *);
typedef void(^NTESAgreeMicHandler)(NSError *);

@interface SHAnchorLiveView ()<NTESLiveInnerViewDelegate, NTESLiveAnchorHandlerDelegate, NTESConnectQueueViewDelegate, NTESTimerHolderDelegate, NIMChatManagerDelegate, NIMSystemNotificationManagerDelegate, NIMNetCallManagerDelegate, NIMChatroomManagerDelegate, NTESLiveAudienceHandlerDelegate>
@property (strong, nonatomic) NIMChatroom *chatroom;
@property (strong, nonatomic) NIMNetCallMeeting *currentMeeting;
@property (strong, nonatomic) NTESMediaCapture *capture;
@property (strong, nonatomic) NTESLiveAnchorHandler *handler;
@property (strong, nonatomic) UIView *captureView;
@property (strong, nonatomic) UIImageView *focusView;

@property (strong, nonatomic) NTESLiveInnerView *innerView;
@property (weak, nonatomic) id<NTESAnchorLiveViewDelegate> delegate;
@property (assign, nonatomic) BOOL isFocusOn;

@property (copy, nonatomic) NTESDisconnectAckHandler ackHandler;
@property (strong, nonatomic) NTESTimerHolder *timer;

@end

@implementation SHAnchorLiveView

+ (instancetype)anchorLiveView{
    return [[SHAnchorLiveView alloc] init];
}

- (instancetype)initWithChatroom:(NIMChatroom *)chatroom currentMeeting:(NIMNetCallMeeting*)currentMeeting capture:(NTESMediaCapture*)capture delegate:(id<NTESAnchorLiveViewDelegate>)delegate{
    self = [super init];
    if (self) {
        _chatroom = chatroom;
        _currentMeeting = currentMeeting;
        _handler = [[NTESLiveAnchorHandler alloc] initWithChatroom:chatroom];
        _handler.delegate = self;
        _delegate = delegate;
        _capture = capture;
        [NTESLiveManager sharedLiveManager].currentMeeting = currentMeeting;
        [self setup];
    }
    return self;
}


- (UIView *)captureView{
    if (_captureView == nil) {
        _captureView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.width, self.height )];
    }
    return _captureView;
}

- (UIImageView *)focusView{
    if (_focusView == nil) {
        _focusView = [[UIImageView alloc] initWithFrame:self.bounds];
        _focusView.image = [UIImage imageNamed:@"icon_focus_frame"];
        _focusView.hidden = YES;
        [_focusView sizeToFit];
    }
    return _focusView;
}

- (NTESLiveInnerView *)innerView{
    if (_innerView == nil) {
        _innerView = [[NTESLiveInnerView alloc] initWithChatroom:self.chatroom.roomId frame:self.bounds];
        [_innerView refreshChatroom:self.chatroom];
        _innerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _innerView.delegate = self;
    }
    return _innerView;
}

- (void)layoutSubviews{
    [super layoutSubviews];
     _captureView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}

- (void)setup{
    self.backgroundColor = SHColor(233, 226, 230);
    [self addSubview:self.captureView];
    [self addSubview:self.focusView];
    
    [[NIMAVChatSDK sharedSDK].netCallManager setVideoCaptureOrientation:[NTESLiveManager sharedLiveManager].orientation];
    
    [[NIMSDK sharedSDK].chatroomManager addDelegate:self];
    [[NIMSDK sharedSDK].chatManager addDelegate:self];
    [[NIMSDK sharedSDK].systemNotificationManager addDelegate:self];
    [[NIMAVChatSDK sharedSDK].netCallManager addDelegate:self];
    
    //视频直播
    if ([NTESLiveManager sharedLiveManager].type == NTESLiveTypeVideo) {
        [_capture switchContainerToView:self.captureView];
        [self.innerView switchToPlayingUI];
        [self addSubview:self.innerView];
        [self.innerView updateQualityButton:[NTESLiveManager sharedLiveManager].liveQuality == NTESLiveQualityHigh];
    }
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self endEditing:YES];
    
    
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    
    //判断是否进行手动对焦显示
    [self doManualFocusWithPointInView:point];
}

#pragma mark NTESLiveInnerViewDelegate
- (void)onCloseLiving{
    if ([NTESLiveManager sharedLiveManager].type == NTESLiveTypeVideo) {
        if ([_delegate respondsToSelector:@selector(onCloseLiving)]) {
            [_delegate onCloseLiveView];
        }
    }
}

- (void)didSendText:(NSString *)text{
    NIMMessage *message = [NTESSessionMsgConverter msgWithText:text];
    NIMSession *session = [NIMSession session:self.chatroom.roomId type:NIMSessionTypeChatroom];
    [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:nil];
}

- (void)onCloseBypassing{
    
    //可能这个时候都没连上,或者连上了在说话
    NTESMicConnector *connector = [[NTESLiveManager sharedLiveManager] connectors:NTESLiveMicStateConnecting].firstObject;
    NSString *uid = connector? connector.uid : [NTESLiveManager sharedLiveManager].connectorOnMic.uid;
    
    SHLog(@"anchor close by passing");
    
    if (connector){
        SHLog(@"anchor close when user is connecting uid: %@",uid);
        //还没有进入房间的情况
        [[NTESLiveManager sharedLiveManager] removeConnectors:uid];
        [self.innerView switchToPlayingUI];
        [self forceDisconnectedUser:uid handler:nil];
    }else{
        //进入房间了，就等等到那个人真的走了
        SHLog(@"anchor close when user is connected uid: %@",uid);
        
        [SVProgressHUD show];
        [self forceDisconnectedUser:uid handler:^(NSError *error) {
            [SVProgressHUD dismiss];
            if (error){
                SHLog(@"on close bypassing error: force disconnect user error %zd",error.code);
     
            }else{
                [self.innerView switchToPlayingUI];
            }
        }];
    }
}

#pragma mark - NIMChatManagerDelegate
- (void)willSendMessage:(NIMMessage *)message{
    switch (message.messageType) {
        case NIMMessageTypeText:
            [self.innerView addMessages:@[message]];
            break;
        default:
            break;
    }
}

- (void)onRecvMessages:(NSArray *)messages{
    for (NIMMessage *message in messages) {
        if (![message.session.sessionId isEqualToString:self.chatroom.roomId]
            && message.session.sessionType == NIMSessionTypeChatroom) {
            //不属于这个聊天室的消息
            return;
        }
        switch (message.messageType) {
            case NIMMessageTypeText:
                [self.innerView addMessages:@[message]];
                break;
            case NIMMessageTypeCustom:{
                NIMCustomObject *object = message.messageObject;
                id<NIMCustomAttachment> attachment = object.attachment;
                if ([attachment isKindOfClass:[NTESPresentAttachment class]]) {
                    [self.innerView addPresentMessages:@[message]];
                }else if ([attachment isKindOfClass:[NTESLikeAttachment class]]) {
                    [self.innerView fireLike];
                }
            }
                break;
            default:
                break;
        }
    }
}

#pragma mark NIMChatroomManagerDelegate
- (void)chatroom:(NSString *)roomId beKicked:(NIMChatroomKickReason)reason{
    if ([roomId isEqualToString:self.chatroom.roomId]) {
        NSString *toast = [NSString stringWithFormat:@"你被踢出聊天室"];
        SHLog(@"chatroom be kicked, roomId:%@  rease:%zd",roomId,reason);
        [SVProgressHUD showInfo:toast];
        [self.capture stopLiveStream];
        [[NIMSDK sharedSDK].chatroomManager exitChatroom:roomId completion:nil];
        [DCURLRouter dismissViewControllerAnimated:YES completion:nil];
    }
}

- (void)chatroom:(NSString *)roomId connectionStateChanged:(NIMChatroomConnectionState)state;{
    SHLog(@"chatroom connection state changed roomId : %@  state : %zd",roomId,state);
}

#pragma mark NIMNetCallManagerDelegate
- (void)onRemoteYUVReady:(NSData *)yuvData width:(NSUInteger)width height:(NSUInteger)height from:(NSString *)user{
    [self.innerView updateRemoteView:yuvData width:width height:height];
}

#pragma mark 连麦者加入
- (void)onUserJoined:(NSString *)uid meeting:(NIMNetCallMeeting *)meeting{
    SHLog(@"on user joined uid %@",uid);
    NTESMicConnector *connector = [[NTESLiveManager sharedLiveManager] findConnector:uid];
    if (connector) {
        connector.state = NTESLiveMicStateConnected;
        [NTESLiveManager sharedLiveManager].connectorOnMic = connector;
        
        //将连麦者的GLView扔到右下角，并显示名字
        [self.innerView switchToBypassStreamingUI:connector];
        
        //发送全局已连麦通知
        [self sendConnectedNotify:connector];
        
        //修改服务器队列
        NTESQueuePushData *data = [[NTESQueuePushData alloc] init];
        data.roomId = self.chatroom.roomId;
        data.ext = [@{@"style":@(connector.type),
                      @"state":@(NTESLiveMicStateConnected),
                      @"info":@{
                              @"nick" : connector.nick.length? connector.nick : connector.uid,
                              @"avatar":connector.avatar.length? connector.avatar : @"avatar_default"}} jsonBody];
        data.uid = uid;
        [[NTESDemoService sharedService] requestMicQueuePush:data completion:nil];
    }
}

#pragma mark 连麦者离开
- (void)onUserLeft:(NSString *)uid meeting:(NIMNetCallMeeting *)meeting{
    NTESMicConnector *connectorOnMic = [NTESLiveManager sharedLiveManager].connectorOnMic;
    if (!connectorOnMic) {
        SHLog(@"error: on mic user is empty!");
        return;
    }
    //修改服务器队列
    NTESQueuePopData *data = [[NTESQueuePopData alloc] init];
    data.roomId = self.chatroom.roomId;
    data.uid    = connectorOnMic.uid;
    
    [[NTESDemoService sharedService] requestMicQueuePop:data completion:^(NSError *error, NSString *ext) {
        if (error) {
            SHLog(@"request mic queue pop error %zd",error.code);
        }
    }];
    
    //修正内存队列
    [[NTESLiveManager sharedLiveManager] removeConnectors:uid];
    [NTESLiveManager sharedLiveManager].connectorOnMic = nil;
    [self.innerView updateConnectorCount:[[NTESLiveManager sharedLiveManager] connectors:NTESLiveMicStateWaiting].count];
    
    //可能是强制要求对面离开，这个时候肯定记录了回调，尝试回调
    if (_ackHandler) {
        _ackHandler(nil);
        _ackHandler = nil;
        _timer = nil;
    }
    
    //发送全局连麦者断开的通知
    [self sendDisconnectedNotify:connectorOnMic];
    
    //切回没有小窗口的画面
    [self.innerView switchToPlayingUI];
}

#pragma mark - NIMSystemNotificationManagerDelegate
#pragma mark 接收自定义消息
- (void)onReceiveCustomSystemNotification:(NIMCustomSystemNotification *)notification{
    NSString *content  = notification.content;
    NSDictionary *dict = [content jsonObject];
    NTESLiveCustomNotificationType type = [dict jsonInteger:@"command"];
    switch (type) {
        case NTESLiveCustomNotificationTypePushMic:
        case NTESLiveCustomNotificationTypePopMic:
        case NTESLiveCustomNotificationTypeRejectAgree:
            [self.handler dealWithBypassCustomNotification:notification];
            break;
        default:
            break;
    }
}

#pragma mark - NTESLiveAnchorHandlerDelegate
- (void)didUpdateConnectors{
    SHLog(@"did update connectors");
    [self.innerView updateConnectorCount:[[NTESLiveManager sharedLiveManager] connectors:NTESLiveMicStateWaiting].count];
}

#pragma mark NTESLiveActionViewDelegate
- (void)onActionType:(NTESLiveActionType)type sender:(id)sender{
    __weak typeof(self) weakSelf = self;
    switch (type) {
        case NTESLiveActionTypeLive://直播
            break;
        case NTESLiveActionTypePresent://礼物
        {
            NTESPresentBoxView *box = [[NTESPresentBoxView alloc] initWithFrame:self.bounds];
            [box show];
        }
            break;
        
        case NTESLiveActionTypeCamera://摄像头
            [self.capture switchCamera];
            break;
            
        case NTESLiveActionTypeInteract://互动
        {
            NTESConnectQueueView *queueView = [[NTESConnectQueueView alloc] initWithFrame:self.bounds];
            queueView.delegate = weakSelf;
            [queueView refreshWithQueue:[[NTESLiveManager sharedLiveManager] connectors: NTESLiveMicStateWaiting]];
            [queueView show];
        }
            break;
            
        case NTESLiveActionTypeBeautify://美颜
            break;
            
        case NTESLiveActionTypeMixAudio://混音
            break;
            
        case NTESLiveActionTypeSnapshot://截图
            break;
            
        case NTESLiveActionTypeShare://分享
            break;
            
        case NTESLiveActionTypeQuality://分辨率
            break;
            
        case NTESLiveActionTypeMirror://镜像
            break;
            
        case NTESLiveActionTypeWaterMark://水印
            break;
            
        case NTESLiveActionTypeFlash://闪光灯
            break;
            
        case NTESLiveActionTypeFocus://开启手动对焦
        
        default:
            break;
    }
}

#pragma mark - NTESConnectQueueViewDelegate
- (void)onSelectMicConnector:(NTESMicConnector *)connector{
    if (connector.state == NTESLiveMicStateWaiting) {
        __weak typeof(self) weakSelf = self;
        NSString *mic = [NTESLiveManager sharedLiveManager].connectorOnMic.uid;
        [SVProgressHUD show];
        if (mic) {
            [self forceDisconnectedUser:mic handler:^(NSError *error) {
                if (error) {
                    [SVProgressHUD dismiss];
                    [SVProgressHUD showInfo:@"切换连麦失败，请重试"];
                }else{
                    [weakSelf agreeMicConnector:connector handler:^(NSError *error) {
                        [SVProgressHUD dismiss];
                    }];
                }
            }];
        }else{
            [self agreeMicConnector:connector handler:^(NSError *error) {
                [SVProgressHUD dismiss];
            }];
        }
    }
}


#pragma mark 手动对焦
- (void)doManualFocusWithPointInView:(CGPoint)point{
    CGFloat actionViewHeight = [self.innerView getActionViewHeight];
    BOOL pointsInRect = point.y < self.height - actionViewHeight;
    //后置摄像头允许对焦
    if ((NIMNetCallMediaType)[NTESLiveManager sharedLiveManager].type == NTESLiveTypeVideo && [self.capture isCameraBack] && _isFocusOn && pointsInRect ) {
        // 代执行的延迟消失数量
        static int delayCount = 0;
        
        // 焦点显示
        self.focusView.center = CGPointMake(point.x, point.y);
        [self bringSubviewToFront:self.focusView];
        self.focusView.hidden = NO;
        
        CGPoint devicePoint = CGPointMake(self.focusView.center.x/self.innerView.frame.size.width, self.focusView.center.y/self.innerView.frame.size.height);
        //对焦
        [[NIMAVChatSDK sharedSDK].netCallManager changeNMCVideoPreViewManualFocusPoint:devicePoint];
        
        delayCount++;
        //3秒自动消失
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (!self.focusView.hidden && delayCount == 1) {
                self.focusView.hidden = YES;
            }
            delayCount--;
        });
    }
}

- (void)forceDisconnectedUser:(NSString *)uid handler:(NTESDisconnectAckHandler)handler{
    if (!uid.length) {
        SHLog(@"force disconnect error : no user id!");
        handler(nil);
        return;
    }
    if (!_ackHandler) {
        //如果 _ackHandler 有值， 说明有一条强制请求已经发出去了，这个时候只要替换掉回调就可以了。
        SHLog(@"send custom notification force disconnect to user %@",uid);
        NIMCustomSystemNotification *notification = [NTESSessionCustomNotificationConverter notificationWithForceDisconnect:self.chatroom.roomId];
        NIMSession *session = [NIMSession session:uid type:NIMSessionTypeP2P];
        [[NIMSDK sharedSDK].systemNotificationManager sendCustomNotification:notification toSession:session completion:nil];
        _timer = [[NTESTimerHolder alloc] init];
        [_timer startTimer:10.0 delegate:self repeats:NO];
    }
    _ackHandler = handler;
}

#pragma mark - NTESTimerHolderDelegate
- (void)onNTESTimerFired:(NTESTimerHolder *)holder{
    if (_ackHandler) {
        NSError *error = [NSError errorWithDomain:NIMRemoteErrorDomain code:NIMRemoteErrorCodeTimeoutError userInfo:nil];
        _ackHandler(error);
    }
    _ackHandler = nil;
}

- (void)agreeMicConnector:(NTESMicConnector *)connector handler:(NTESAgreeMicHandler)handler{
    __weak typeof(self) weakSelf = self;
    NIMCustomSystemNotification *notification = [NTESSessionCustomNotificationConverter notificationWithAgreeMic:self.chatroom.roomId style:connector.type];
    NIMSession *session = [NIMSession session:connector.uid type:NIMSessionTypeP2P];
    SHLog(@"anchor: agree mic: %@",connector.uid);
    [[NIMSDK sharedSDK].systemNotificationManager sendCustomNotification:notification toSession:session completion:^(NSError * _Nullable error) {
        if (!error) {
            connector.state = NTESLiveMicStateConnecting;
            [[NTESLiveManager sharedLiveManager] updateConnectors:connector];
            //显示连接中的图案
            [weakSelf.innerView switchToBypassLoadingUI:connector];
            //刷新等待列表人数
            [weakSelf.innerView updateConnectorCount:[[NTESLiveManager sharedLiveManager] connectors:NTESLiveMicStateWaiting].count];
        }else{
            SHLog(@"notification with agree mic error: %@",error);
            [SVProgressHUD showInfo:@"选择失败，请重试"];
        }
        if (handler) {
            handler(error);
        }
    }];
}

#pragma mark 发送全局连麦者断开的通知
- (void)sendDisconnectedNotify:(NTESMicConnector *)connector{
    NIMMessage *message = [NTESSessionMsgConverter msgWithDisconnectedMic:connector];
    NIMSession *session = [NIMSession session:self.chatroom.roomId type:NIMSessionTypeChatroom];
    [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:nil];
}


- (void)sendConnectedNotify:(NTESMicConnector *)connector{
    NIMMessage *message = [NTESSessionMsgConverter msgWithConnectedMic:connector];
    NIMSession *session = [NIMSession session:self.chatroom.roomId type:NIMSessionTypeChatroom];
    [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:nil];
}

- (void)dealloc{
    [[NIMSDK sharedSDK].chatroomManager removeDelegate:self];
    [[NIMSDK sharedSDK].chatManager removeDelegate:self];
    [UIApplication sharedApplication].idleTimerDisabled = NO;
}

@end
